

// 日志消息格式化模块
//[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n
//%d:时间 {%H:%M:%S}子格式
//%t线程ID
//%c日志器,%f:文件名,%l:行号,%p日志等级,%T:制表符,%m:正文,%n:换行符

// 该模块主要包含两部分：格式化字符串，格式化子项数组
// 不同的格式化字符串对应不同的格式化子项数组
#ifndef _M_FORMAT_H__
#define _M_FORMAT_H__
#include "logLevel.hpp"
#include "logMessage.hpp"
#include <memory>
#include <string>
#include <vector>
#include <sstream>
#include <string>
#include <cassert>
#include <utility>

namespace xglog
{
    // 格式化子项数组定义
    // 基类
    class FormatItem
    {
    public:
        virtual void format(std::ostream &out, const logMessage &logMsg) = 0;
    };
    using FormatPtr = std::shared_ptr<FormatItem>;

    // 1,时间项,时间有特定的格式
    class TimeFormat : public FormatItem
    {
    private:
        std::string _format;

    public:
        TimeFormat(const std::string &format = "%H:%M:%S")
            : _format(format)
        {
        }
        void format(std::ostream &out, const logMessage &logMsg)
        {
            time_t _time = logMsg._current_time;
            struct tm c;
            localtime_r(&_time, &c);
            char tmp[128];
            strftime(tmp, 127, _format.c_str(), &c);
            out << tmp;
        }
    };
    // 2,日志等级项
    class LevelFormat : public FormatItem
    {
    public:
        void format(std::ostream &out, const logMessage &logMsg)
        {
            out << LogLevel::toString(logMsg._level);
        }
    };
    // 3,线程ID项
    class ThreadFormat : public FormatItem
    {
    public:
        void format(std::ostream &out, const logMessage &logMsg)
        {
            out << logMsg._tid;
        }
    };
    // 4,行号项
    class LineFormat : public FormatItem
    {
    public:
        void format(std::ostream &out, const logMessage &logMsg)
        {
            out << logMsg._line;
        }
    };
    // 5,文件名项
    class FileFormat : public FormatItem
    {
    public:
        void format(std::ostream &out, const logMessage &logMsg)
        {
            out << logMsg._file;
        }
    };
    // 6,日志器项
    class LoggerFormat : public FormatItem
    {
    public:
        void format(std::ostream &out, const logMessage &logMsg)
        {
            out << logMsg._logger;
        }
    };
    // 7,消息内容项
    class MsgFormat : public FormatItem
    {
    public:
        void format(std::ostream &out, const logMessage &logMsg)
        {
            out << logMsg._msg;
        }
    };
    // 8,制表符
    class TabFormat : public FormatItem
    {
    public:
        void format(std::ostream &out, const logMessage &logMsg)
        {
            out << "\t";
        }
    };
    // 9,换行符
    class NLineFormat : public FormatItem
    {
    public:
        void format(std::ostream &out, const logMessage &logMsg)
        {
            out << "\n";
        }
    };
    // 10,其他选项
    class OtherFormat : public FormatItem
    {
    public:
        OtherFormat(const std::string &msg)
            : _msg(msg)
        {
        }
        void format(std::ostream &out, const logMessage &logMsg)
        {
            out << _msg;
        }

    private:
        std::string _msg; // 其他信息,比如[ ] ,
    };

    // 日志格式化模块
    class Formatter
    {
    public:
        using ptr=std::shared_ptr<Formatter>;
        Formatter(std::string pattern = "[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n")
            : _pattern(pattern)
        {
            assert(parsePattern());
        }
        // 对外提供的接口——格式化日志
        void Format(std::ostream &out, const logMessage &logMsg)
        {
            // 根据格式化子项数组的顺序构建日志
            for (auto &item : _items)
            {
                item->format(out, logMsg);
            }
        }
        std::string format(const logMessage &logMsg)
        {
            std::stringstream ss;
            Format(ss, logMsg);
            return ss.str();
        }

    private:
        // 解析格式
        // 根据_pattern，构建对应的格式化子项，加入_items格式化子项数组中
        bool parsePattern()
        {
            // 1,先解析，将解析结果使用数组保存下来
            std::vector<std::pair<std::string, std::string>> fmt_res;
            size_t pos = 0;
            size_t n = _pattern.size();
            std::string key, val;

            while (pos < n)
            {
                // 判断是否为格式化字符
                if (_pattern[pos] != '%')
                {
                    val.push_back(_pattern[pos++]);
                    continue;
                }
                // 是格式化字符,判断是不是%%——表示一个%
                if (pos + 1 < n && _pattern[pos + 1] == '%')
                {
                    val.push_back('%');
                    pos += 2;
                    continue;
                }
                if (!val.empty())
                {
                    fmt_res.push_back({"", val});
                    val.clear();
                }

                // 走到这说明是格式化字符
                pos += 1; // pos指向格式化字符
                if(pos==n)
                {
                    std::cout<<"%后没有对应的格式化字符"<<std::endl;
                    return false;
                }
                if (pos < n)
                {
                    key = _pattern[pos];
                    // 判断有没有子格式
                    pos += 1;
                    if (pos < n && _pattern[pos] == '{')
                    {
                        pos += 1;
                        while (pos < n && _pattern[pos] != '}')
                        {
                            val.push_back(_pattern[pos++]);
                        }
                        if (pos == n)
                        {
                            std::cout << "输入格式字符有误，没有匹配的 }" << std::endl;
                            return false;
                        }
                        pos++;
                    }
                }
                fmt_res.push_back({key, val});
                key.clear();
                val.clear();
            }
            // 2,根据结果数组中的key,val去构建对应的格式化子项
            for (auto &[k, v] : fmt_res)
            {
                // std::cout << k << v << std::endl;//for debug
                _items.push_back(createFormat(k, v));
            }
            return true;
        }
        // 创建子项化数组格式
        // key代表格式化字符,val代表对应的子格式
        // key为空,说明是普通字符，不需要进行格式化，构建other格式化子项
        // val为空，说明没有对应的子格式
        FormatPtr createFormat(const std::string &key, const std::string &val)
        {
            //[%d:{%H:%M:%s}] [%t] [%c] [%f:%l] [%T] %m%n
            //%d:时间 {%H:%M:%S}子格式
            //%t线程ID,%c日志器,%f:文件名,%l:行号,%T:制表符,%m:正文,%n:换行符
            //[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n
            if (key == "d")
                return std::make_shared<TimeFormat>(val);
            if (key == "t")
                return std::make_shared<ThreadFormat>();
            if (key == "c")
                return std::make_shared<LoggerFormat>();
            if (key == "f")
                return std::make_shared<FileFormat>();
            if (key == "l")
                return std::make_shared<LineFormat>();
            if (key == "T")
                return std::make_shared<TabFormat>();
            if (key == "m")
                return std::make_shared<MsgFormat>();
            if (key == "n")
                return std::make_shared<NLineFormat>();
            if (key == "p")
                return std::make_shared<LevelFormat>();
            if (key == "")
                return std::make_shared<OtherFormat>(val);
            std::cout<<"对应的格式化字符信息错误"<<std::endl;
            abort();
            return nullptr;
        }

    private:
        std::string _pattern;          // 日志格式化
        std::vector<FormatPtr> _items; // 格式化子项数组
    };
}

#endif